import { _decorator, AudioSource, Camera, Color, Component, geometry, instantiate, Node, PhysicsSystem, Prefab, resources, Sprite, SpriteFrame, tween, UITransform, Vec3 } from 'cc';
import { CardClickManager } from './CardClickManager';
import { GLOBALUtil } from './GlobalUtil';
import { GLOBALVar } from './GlobalVar';
import { GLOBALPOP } from './GlobalPop';
const { ccclass, property } = _decorator;

enum PileType {
    ONE_PILE_ONE,
    ONE_PILE_TWO,
    ONE_PILE_FOUR
}
const CARD_WIDTH: number = 80;
const CARD_HEIGHT: number = 100;

@ccclass('CardGenerate')
class CardGenerate extends Component {

    /*
    此类用于编写一套统一的卡牌生成规则，供外部调用。
    1.卡牌坐标用三维坐标表示，x轴表示横坐标，y轴表示纵坐标，z轴表示层数。
    2.难度控制：卡牌总数，层数，卡牌种类
    3.卡牌堆砌的三种模式：1.一压一，2.一压二，3.一压四
    */
    private static _instance: CardGenerate = null;
    private CommonCardPrefabs: Prefab[] = [];
    private SpecialCardPrefabs: Prefab[] = [];
    private CardsInMap: Node[] = [];
    private CurrentCamera: Camera = null;
    private CardContainer: Node = null;

    private OffSets: {x: number, y: number}[] = [
        {x: -38, y:-48},
        {x: 38, y:-48},
        {x: -38, y:48},
        {x: 38, y:48},
    ];

    //坐标对象，包含各个不同类型的坐标数组
    //1.CoorFullMap表示全地图随机生成卡牌可取坐标，即卡牌上下左右移动1/2卡牌宽高 * n，即可实现卡牌的三种堆砌模式
    private Coordinate: [number, number] | null = null;
    private CoordinateMap: { [key: string]: [number, number][] } = {};
    public static getInstance(): CardGenerate {
        if (this._instance == null) {
            this._instance = new CardGenerate();
        }
        return this._instance;
    }
    
    public setCurrentCamera(camera: Camera) {
        this.CurrentCamera = camera;
    }
    public setCardContainer(node: Node) {
        this.CardContainer = node;
    }

    //初始化卡牌预制体
    private initCardPrefabs(TypeNums: number): Promise<any>[] {
        //初始化数组
        this.CommonCardPrefabs = [];
        //TODO:动态随机加载卡牌prefab
        if (TypeNums > 14) {
            console.error("所取卡牌种类数量大于卡牌总种类数量")
            return;
        }
        if (TypeNums <= 0) {
            console.error("卡牌种类数量不能小于1");
            return;
        }

        const RANDOMNUM: number[] = GLOBALUtil.getMultiRandomInt(TypeNums, 0, 14)
        let loadPromise = RANDOMNUM.map((value, index) => {
            return new Promise((resolve, reject) => {
                resources.load("CardPrefabs/Card_" + value, Prefab, (err, prefab) => {
                    if (err) {
                        console.error(err);
                        reject(err);
                        return;
                    } else {
                        this.CommonCardPrefabs.push(prefab);
                        resolve(prefab);
                    }
                })
            })
        })

        //特殊卡牌每次都是加满
        for (let i = 1; i <= 2; i++) {
            loadPromise.push(new Promise((resolve, reject) => {
                resources.load("CardPrefabs/SpecialCard_" + i, Prefab, (err, prefab) => {
                    if (err) {
                        console.error(err);
                        reject(err);
                        return;
                    } else {
                        this.SpecialCardPrefabs.push(prefab);
                        resolve(prefab);
                    }
                })
            }))
        }
        return loadPromise;
    }

    private initCoordinates(CircleNum: number, CardContainer: Node) {
        /*CircleNum表示向外拓展的圈数，
        中心点的卡牌不算的情况下，
        最多可以向外拓展三圈，只有一圈的话太少，
        因此CircleNum可取值为2或3。
        */
       if (CircleNum != 2 && CircleNum != 3) {
            console.error("CircleNum must be 2 or 3");
       } else {
            //初始化对象
            this.CoordinateMap["CoorFullMap"] = [];
            let ParentWorldPos = CardContainer.getWorldPosition();
            //因为圈数是以卡牌平铺来计算出的，但是坐标偏移只有卡牌宽高的1/2，所以要乘以2
            for (let i = -CircleNum*2; i <= CircleNum*2; i++) {
                for (let j = -CircleNum*2; j <= CircleNum*2; j++) {
                    //i控制行，j控制列
                    let x = 0.5 * CARD_WIDTH * j + ParentWorldPos.x;
                    let y = 0.5 * CARD_HEIGHT * i + ParentWorldPos.y;
                    this.Coordinate = [x, y]
                    this.CoordinateMap["CoorFullMap"].push(this.Coordinate);
                }
            }
       }
    }


    //1.普通卡牌全图随机生成方法
    public generateCommonCardFullMap(CardTypeNum:number, CardTotalNum:number, CircleNum:number, Parent: Node, callback?: Function) {
        if (CardTotalNum % 3 != 0) {
            console.error("CardTotalNum must be a multiple of 3");
            return;
        }
        if (CardTypeNum * 3 > CardTotalNum) {
            console.error("卡牌总数不足");
            return;
        }

        
        let promise = this.initCardPrefabs(CardTypeNum);    //随机挑选卡牌种类
        this.initCoordinates(CircleNum, Parent);    //生成坐标点
        //resources.load是异步函数，等待所有资源加载完成后执行then方法
        Promise.all(promise).then((values) => {
            console.log("卡牌加载完成")
            //生成每种卡牌的数量
            let PerCardPrefabNum: Map<number, number> = new Map();
            for (let i = 0; i < CardTotalNum; i += 3) {
                let RandomInt = GLOBALUtil.getSingleRandomInt(this.CommonCardPrefabs.length);
                let CurrentNum = PerCardPrefabNum.get(RandomInt);
                CurrentNum ? PerCardPrefabNum.set(RandomInt, CurrentNum + 3) : PerCardPrefabNum.set(RandomInt, 3);
            }

            let zIDX = 0; //储存Z轴的值
            //从PerCardPrefabNum中随机取出key对应的prefab，取完一次后key对应的value减1，直到所有值都为0
            while (PerCardPrefabNum.size > 0) {
                let PerCardPrefabNumNotZero: number[] = []; //用于连续储存value非0的key
                PerCardPrefabNum.forEach((value, key) => {
                    if (value === 0) {
                        PerCardPrefabNum.delete(key);
                    } else {
                        PerCardPrefabNumNotZero.push(key);
                    }
                })
                if (PerCardPrefabNum.size === 0) {
                    break;
                }
                const TEMP_NUM = GLOBALUtil.getSingleRandomInt(PerCardPrefabNumNotZero.length); //从数组中随机取值
                let RandomInt = GLOBALUtil.getSingleRandomInt(this.CoordinateMap["CoorFullMap"].length); //从坐标中随机取值
                let Card: Node = instantiate(this.CommonCardPrefabs[PerCardPrefabNumNotZero[TEMP_NUM]]);
                let vec3 = new Vec3(this.CoordinateMap["CoorFullMap"][RandomInt][0], this.CoordinateMap["CoorFullMap"][RandomInt][1], zIDX);
                zIDX += 1; //改变z轴坐标用于射线检测
                Card.parent = Parent;
                Card.setWorldPosition(vec3);
                Card.name = "Card_" + zIDX;
                this.CardsInMap.push(Card);
                PerCardPrefabNum.set(PerCardPrefabNumNotZero[TEMP_NUM], PerCardPrefabNum.get(PerCardPrefabNumNotZero[TEMP_NUM]) - 1);
                PerCardPrefabNumNotZero = []; //清空数组
            }
            callback();
        }).catch((error) => {
            console.error("加载卡牌预制体失败", error);
        })
    }
    
    //射线检测卡牌遮挡关系
    public initCardCover(Camera: Camera) {
        this.CurrentCamera = Camera;
        let ray = new geometry.Ray();
        this.CardsInMap.forEach((CARD) => {
            //上下左右射线检测
            this.OffSets.forEach((v) => {
                const WorldPos = CARD.getWorldPosition();
                WorldPos.x += v.x;
                WorldPos.y += v.y;
                const ScreenPos = Camera.worldToScreen(WorldPos);
                const CARD_NAME = CARD.name;
                Camera.screenPointToRay(ScreenPos.x, ScreenPos.y, ray);
                if (PhysicsSystem.instance.raycastClosest(ray)) {
                    const raycastClosestResult = PhysicsSystem.instance.raycastClosestResult;
                    const collider = raycastClosestResult.collider;
                    const hitPoint = raycastClosestResult.hitPoint;
                    const hitNormal = raycastClosestResult.hitNormal;
                    const distance = raycastClosestResult.distance;
                    const _CARD = collider.node;
                    const name = _CARD.name;
                    // console.log(hitPoint)
                    if (name === CARD_NAME) {
                        const TS = _CARD.getComponent("CardClickManager") as CardClickManager;
                        const CARD_RAY_COUNT = TS.getCardrayCount();
                        TS.setCardrayCount(CARD_RAY_COUNT + 1);
                    }
                }
            })
        })
    }

    public updateCardCover(POS: Vec3) {
        //传入的是卡牌坐标，因为卡牌在移动，如果动态获取的话坐标也会一直变。
        let ray = new geometry.Ray();
        this.OffSets.forEach((v) => {
            const WorldPos = new Vec3(POS.x + v.x, POS.y + v.y, POS.z);
            const ScreenPos = this.CurrentCamera.worldToScreen(WorldPos);
            this.CurrentCamera.screenPointToRay(ScreenPos.x, ScreenPos.y, ray);
            if (PhysicsSystem.instance.raycastClosest(ray)) {
                const raycastClosestResult = PhysicsSystem.instance.raycastClosestResult;
                const collider = raycastClosestResult.collider;
                const _CARD = collider.node;
                const name = _CARD.name;
                const TS = _CARD.getComponent("CardClickManager") as CardClickManager;
                TS.setCardrayCount(TS.getCardrayCount() + 1);
            }
        })
    }
    //给外部提供地图中的卡牌数组
    public getCardsInMap() {
        return this.CardsInMap;
    }
    //初始化成员，确保生成卡牌的时候成员是空的，地图上也是空的
    private initMembers() {
        //消灭地图上的卡牌
        this.CardsInMap.forEach((card) => {
            card.destroy();
        })
        this.Coordinate = null;
        this.CoordinateMap = {};
        this.CardsInMap = [];
        GLOBALVar.clearCardInSlot();
    }

    //关卡生成
    public generateLevel() {
        this.initMembers();
        let level = GLOBALVar.getClassicModeLevel();
        let CardTypeNum: number;
        let CardTotalNum: number;
        let CircleNum: number;
        switch (level) {
            case 1:
                CardTypeNum = 5;
                CardTotalNum = 15;
                CircleNum = 2;
                break;
            case 2:
                CardTypeNum = 10;
                CardTotalNum = 30;
                CircleNum = 2;
                break;
            case 3:
                CardTypeNum = 14;
                CardTotalNum = 66;
                CircleNum = 3;
                break;
        }
        this.generateCommonCardFullMap(CardTypeNum, CardTotalNum, CircleNum, this.CardContainer, () => {
            console.log("卡牌生成完毕");
            setTimeout(() => {
            //卡牌生成完后用射线检测卡牌的遮挡关系
            this.initCardCover(this.CurrentCamera);
            }, 500)
        })
    }

    //重新开始
    public restart() {
        GLOBALVar.setClassicModeLevel(1);
        GLOBALPOP.setGameState(1);
        this.generateLevel();
    }
    //播放通关声音
    public playYouPass() {
        this.CardContainer.getComponent(AudioSource).play();
    }
}
//卡牌生成大法器
export const CardGenerator: CardGenerate = CardGenerate.getInstance();

